﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ModelQuality.Metrics.Model;
using ModelQuality.Metrics.Rules;

namespace ModelQuality.Metrics.Engine
{
    static class Projections
    {
        public interface IProjection<T>
        {
            IList<Object> Apply(T sourceObject, IValidationContext validationContext);
        }

        public static IProjection<ElementVO> From(AttributeName attributeName)
        {
            IProjection<ElementVO> proj = null;
            switch (attributeName)
            {
                case AttributeName.STATUS:
                    proj = new StatusProjection();
                    break;
                case AttributeName.NOTES:
                    proj = new NotesProjection();
                    break;
                case AttributeName.NAME:
                    proj = new NameProjection();
                    break;
                case AttributeName.GENTYPE:
                    proj = new GenTypeProjection();
                    break;
                case AttributeName.SCENARIOS:
                    proj = new ScenariosProjection();
                    break;
                case AttributeName.DIAGRAMS:
                    proj = new DiagramsProjection();
                    break;
                case AttributeName.METHODS:
                    proj = new MethodsProjection();
                    break;
            }

            return proj;
        }

        public static IProjection<DiagramVO> From(CheckType checkType)
        {
            IProjection<DiagramVO> proj = null;

            switch (checkType)
            {
                case CheckType.ELEMENTS_NUMBER:
                    proj = new ElementsNumberProjection();
                    break;
                case CheckType.ELEMENTS_TYPES:
                    proj = new ElementTypesProjection();
                    break;
            }

            return proj;
        }

        class StatusProjection : IProjection<ElementVO>
        {
            #region IProjection<ElementVO> Membres

            public IList<Object> Apply(ElementVO element, IValidationContext validationContext)
            {
                return new List<Object> { element.Status };
            }

            #endregion
        }

        class NotesProjection : IProjection<ElementVO>
        {
            #region IProjection<ElementVO> Membres

            public IList<Object> Apply(ElementVO element, IValidationContext validationContext)
            {
                return new List<Object> { element.Description };
            }

            #endregion
        }

        class NameProjection : IProjection<ElementVO>
        {
            #region IProjection<ElementVO> Membres

            public IList<Object> Apply(ElementVO element, IValidationContext validationContext)
            {
                return new List<Object> { element.Name };
            }

            #endregion
        }

        class GenTypeProjection : IProjection<ElementVO>
        {
            #region IProjection<ElementVO> Membres

            public IList<Object> Apply(ElementVO element, IValidationContext validationContext)
            {
                return new List<Object> { element.GenType };
            }

            #endregion
        }

        class ScenariosProjection : IProjection<ElementVO>
        {
            #region IProjection<ElementVO> Membres

            public IList<Object> Apply(ElementVO element, IValidationContext validationContext)
            {
                return validationContext.RepositoryServices.GetScenarios(element).ToArray();
            }

            #endregion
        }

        class DiagramsProjection : IProjection<ElementVO>
        {
            #region IProjection<ElementVO> Membres

            public IList<Object> Apply(ElementVO element, IValidationContext validationContext)
            {
                return validationContext.RepositoryServices.GetDiagrams(element).ToArray();
            }

            #endregion
        }

        class MethodsProjection : IProjection<ElementVO>
        {
            #region IProjection<ElementVO> Membres

            public IList<Object> Apply(ElementVO element, IValidationContext validationContext)
            {
                return validationContext.RepositoryServices.GetOperations(element).ToArray();
            }

            #endregion
        }

        class ElementsNumberProjection : IProjection<DiagramVO>
        {
            #region IProjection<DiagramVO> Membres

            public IList<Object> Apply(DiagramVO diagram, IValidationContext validationContext)
            {
                var elems = validationContext.RepositoryServices.GetElementsFromDiagram(diagram);
                return new List<Object> { elems.Count };
            }

            #endregion
        }

        class ElementTypesProjection : IProjection<DiagramVO>
        {
            #region IProjection<DiagramVO> Membres

            public IList<Object> Apply(DiagramVO diagram, IValidationContext validationContext)
            {
                var elems = validationContext.RepositoryServices.GetElementsFromDiagram(diagram);
                return elems.Select(elem => FormatElementType(elem.ElementType)).ToArray();
            }

            #endregion

            /// <summary>
            /// REQUIREMENT => requirement => Requirement
            /// </summary>
            /// <param name="type"></param>
            /// <returns></returns>
            private String FormatElementType(ElementType type)
            {
                StringBuilder tmp = new StringBuilder(type.ToString().ToLower());
                tmp[0] = Char.ToUpper(tmp[0]);

                return tmp.ToString();
            }
        }
    }
}
